﻿
using com.iot.core.boot;
using com.iot.core.data;
using com.iot.core.data.entity;
using com.iot.core.exception;
using com.iot.core.infrastructure;
using com.iot.core.manager.auth;
using com.iot.core.manager.htcls;
using com.iot.core.manager.htctl;
using com.iot.core.manager.id;
using com.iot.core.util;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using MySqlX.XDevAPI.Common;
using NLog.Fluent;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Collections.Specialized.BitVector32;


namespace com.iot.core.boot
{
    public class MyFilter : IAsyncActionFilter, IAsyncResultFilter
    {
        public async Task OnActionExecutionAsync(
            ActionExecutingContext context, ActionExecutionDelegate next )
        {
            // Do something before the action executes.
            try
            {
                var myContext=EngineContext.Current.Resolve<MyContext>();
                var htUserLoginMapper = EngineContext.Current.Resolve<IRepository<HtUserLogin>>();

                var ctlName = context.Controller.GetType().FullName;
                var actName = context.ActionDescriptor.DisplayName;
                actName=actName.Split(new char[] {' '},StringSplitOptions.RemoveEmptyEntries)[0];
                actName = actName.Substring(actName.LastIndexOf(".") + 1).Trim();
                if (actName.EndsWith("Async"))
                {
                    actName = actName.Substring(0, actName.Length - 5);
                }
                var req=context.HttpContext.Request;
                var token = req.Headers.ContainsKey("token")?req.Headers["token"].ToString():"";
                var reqUrl = req.Path.ToString().ToLower();
                var mctl = HtCtlManager.Current.getCtl(ctlName);
                var maction = HtCtlManager.Current.GetAction(mctl.FullName , actName);
                 
                myContext.Action = maction;

                var su = myContext.Su;
                if (token!="")
                {
                    var su2 = AuthManager.Current.GetSuByToken(token);
                    if (su2!=null)
                    {
                        htUserLoginMapper.EntityToDto(su2, su); 
                    }
                }
                su.EdtUrl = reqUrl;
                su.EdtDt = DateTime.Now;

                if (string.IsNullOrEmpty(su.Os))
                {
                    su.Os = RequestUtil.GetOS(context.HttpContext);
                } 
                if (string.IsNullOrEmpty(su.Browser))
                {
                    su.Browser = RequestUtil.GetBrowserName(context.HttpContext);
                }
                if (string.IsNullOrEmpty(su.Ip))
                {
                    su.Ip = RequestUtil.GetClientIP(context.HttpContext);
                }
                var mylog = myContext.MyLog;
                htUserLoginMapper.EntityToDto(su, mylog);
                mylog.Id= HtIdManager.Current.NextLong();
                mylog.CrtDt = DateTime.Now;
                mylog.Host = req.Host.Host + ":" + req.Host.Port.ToString();
                mylog.HtuserloginId = su.Id;
                mylog.Url = su.EdtUrl;

                if(maction!=null)
                {
                    var bHasUrl=await AuthManager.Current.HasUrlAsync(su, maction);
                    if (!bHasUrl)
                    {
                        throw new MyException( ExceptionEnum.Unauthorized);
                    }
                }

                var LogNeed = false;
                if (maction != null)
                {
                    LogNeed = maction.LogNeed ||  su.Debug;
                }

                object Pin = null;
                if (maction != null && maction.PinName != "")
                {
                    Pin = context.ActionArguments[maction.PinName];

                    if (Pin != null)
                    {
                        ValidatorUtils.validateEntity(Pin);
                    }

                    HtClsManager.Current.DealParam(Pin);
                     
                    if (LogNeed && maction.LogPin)
                    {
                         mylog.Pin = MyJSON.ToJSONString(Pin);
                    }
                    mylog.Glid = HtClsManager.Current.GetFieldStrV(Pin, "Id");
                }
                myContext.Pin = Pin;
                  
                var r = await next();
                 

            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            try
            {
                var myContext = EngineContext.Current.Resolve<MyContext>();
                var htActionLogMapper = EngineContext.Current.Resolve<IRepository<HtActionLog>>();
                var LogNeed = false;
                var maction = myContext.Action;
                var su = myContext.Su;
                var mylog = myContext.MyLog;
                if (maction != null)
                {
                    LogNeed = maction.LogNeed || su.Debug;
                }


                var resultContext = context;
                var Pout = "";
                object OPout = null;
                if (resultContext.Result is ObjectResult r)
                {
                    var v = r.Value;
                    OPout = v;
                    if (v is MyApiResult)
                    {
                        if (LogNeed && maction.LogPout)
                        {
                            Pout = MyJSON.ToJSONString(v);
                        }
                    }
                    else
                    {
                        var d = MyApiResult.Success(r.Value);
                        var modelState = context.ModelState;
                        if (!modelState.IsValid)
                        {
                            d.Code = 10;
                            d.Msg = "参数错误";
                            if (r.Value is ValidationProblemDetails v2)
                            {
                                d.Msg += ":" +
                                    string.Join("\n", v2.Errors.Select(a => a.Value).SelectMany(b => b).ToList());
                                d.Data = "";
                            }
                        }
                        else
                        {
                            if (LogNeed && maction.LogPout)
                            {
                                Pout = MyJSON.ToJSONString(r.Value);
                            }
                        }
                        resultContext.Result = new ObjectResult(d);
                    }
                }
                if (LogNeed)
                {
                    if (mylog.Pin.Length > 2000)
                    {
                        mylog.Pin = mylog.Pin.Substring(0, 2000);
                    }
                    mylog.Pout = Pout;
                    if (mylog.Pout.Length > 2000)
                    {
                        mylog.Pout = mylog.Pout.Substring(0, 2000);
                    }
                    mylog.Mseconds = Convert.ToInt32((DateTime.Now - mylog.CrtDt).TotalMilliseconds);
                    DealLogMemo(myContext, maction, OPout);
                    htActionLogMapper.DB.ChangeTracker.Clear();
                    htActionLogMapper.Insert(mylog, false);
                    htActionLogMapper.SaveChagnesAsync();
                }

                await next();
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        void DealLogMemo(MyContext myContext, HtCtlActDto mact, Object pout)
        {
            try
            {

                DealLogMemoF(myContext, mact, pout);
            }
            catch (Exception ex)
            {
                     
            }
        }
        void DealLogMemoF(MyContext myContext, HtCtlActDto mact, Object pout)
        {
            var mylog = myContext.MyLog;
            if (mylog == null)
            {
                return;
            }
            if (mact == null)
            {
                return;
            }
            if (!string.IsNullOrWhiteSpace(mylog.Memo))
            {
                return;
            }


            var ActionName = mact.Name;
            var LogTemplete = mact.LogTemplete;
            LogTemplete = LogTemplete.Replace("{ActionName}", ActionName);
            //{ActionName} {Pin.Name}  {Deleted.Name}  {Deleteds.Name} {Inserted.Name} {Inserteds.Count}
            //Pout
            var ib = LogTemplete.IndexOf("{");
            while (ib >= 0)
            {
                var ie = LogTemplete.IndexOf("}", ib);
                if (ie < 0)
                {
                    break;
                }
                var field = LogTemplete.Substring(ib + 1, ie-ib-1).Trim();
                var arr = field.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                if (arr.Length != 2)
                {
                    break;
                }
                switch (arr[0])
                {
                    case "Pin":
                        {
                            var svr = HtClsManager.Current.GetFieldStrV(myContext.Pin, arr[1]);
                            LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                        }
                        break;
                    case "Pout":
                        {
                            var svr = HtClsManager.Current.GetFieldStrV(pout, arr[1]);
                            LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                        }
                        break;
                    case "Inserted":
                        {
                            var svr = HtClsManager.Current.GetFieldStrV(myContext.Inserted, arr[1]);
                            LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                        }
                        break;
                    case "Inserteds":
                        {
                            if (arr[1].Equals("Count"))
                            {
                                var svr = "" + myContext.Inserteds.Count.ToString();
                                LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                            }
                            else if (myContext.Inserteds.Count > 0)
                            {
                                var svr = "";
                                foreach (var mdto in myContext.Inserteds)
                                {
                                    svr += HtClsManager.Current.GetFieldStrV(mdto, arr[1]) + ",";
                                }
                                svr = svr.TrimEnd(new char[] { ',' });
                                LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                            }
                        }
                        break;

                    case "Deleted":
                        {
                            var svr = HtClsManager.Current.GetFieldStrV(myContext.Deleted, arr[1]);
                            LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                        }
                        break;

                    case "Deleteds":
                        {
                            if (arr[1].Equals("Count"))
                            {
                                var svr = "" + myContext.Deleteds.Count.ToString();
                                LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                            }
                            else if (myContext.Deleteds.Count > 0)
                            {
                                var svr = "";
                                foreach (var mdto in myContext.Deleteds)
                                {
                                    svr += HtClsManager.Current.GetFieldStrV(mdto, arr[1]) + ",";
                                }
                                svr = svr.TrimEnd(new char[] { ',' });
                                LogTemplete = LogTemplete.Replace("{" + field + "}", svr);
                            }
                        }
                        break;
                    default:
                        break;
                }



                ib = LogTemplete.IndexOf("{");
            }

            if (string.IsNullOrEmpty(LogTemplete))
            {
                LogTemplete = ActionName;
            }
            mylog.Memo = LogTemplete;
        }
            
    }
}
